home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
lisp
/
kcl
/
akcl
/
kcl.lha
/
ild
/
ild.c
next >
Wrap
C/C++ Source or Header
|
1986-05-24
|
7KB
|
314 lines
/*
ild: incremental linker/loader on System V
(C) Masami Hagiya, 1986
Usage:
% ild loading_object start_address \
loaded_object output_file
The start address is in decimal.
How to Create:
To compile this file (ild.c) and make ild, do the following.
% cc -o ild ild.c -lld
Problem:
This program only supports the simplest linear search for symbols.
*/
#include <stdio.h>
#include <filehdr.h>
#include <aouthdr.h>
#include <scnhdr.h>
#include <reloc.h>
#include <syms.h>
#include <storclass.h>
#include <ldfcn.h>
struct filehdr my_header;
struct syment *my_symbol_table;
char *my_string_table;
struct filehdr header;
struct scnhdr section[9];
char *text;
struct syment *symbol_table;
char *string_table;
char *start_address;
struct reloc relocation_info;
main(argc, argv)
int argc;
char *argv[];
{
if (argc < 5) {
fprintf(stderr, "Arg count.\n");
exit(1);
}
/*
printf("ild %s %s %s %s\n", argv[1], argv[2], argv[3], argv[4]);
fflush(stdout);
*/
get_myself(argv[1]);
/*
printf("Myself got.\n");
fflush(stdout);
*/
start_address = (char *)atoi(argv[2]);
fasload(argv[3], argv[4]);
exit(0);
}
get_myself(filename)
char *filename;
{
int i;
LDFILE *ldptr;
extern char *malloc();
ldptr = ldopen(filename, NULL);
if (ldptr == NULL) {
fprintf(stderr, "Can't open %s\n", filename);
exit(1);
}
ldfhread(ldptr, &my_header);
ldtbseek(ldptr);
my_symbol_table
= (struct syment *)malloc(sizeof(struct syment) * my_header.f_nsyms);
/*
sizeof(struct syment) and SYMESZ are not always the same.
*/
for (i = 0; i < my_header.f_nsyms; i++)
FREAD(&my_symbol_table[i], SYMESZ, 1, ldptr);
/*
If the string table is not empty,
its length is stored after the symbol table,
This is not described in the manual, and may change in the future.
*/
if (FREAD(&i, 4, 1, ldptr) > 0) {
my_string_table = malloc(i);
FSEEK(ldptr, -4, 1);
FREAD(my_string_table, 1, i, ldptr);
}
ldclose(ldptr);
}
fasload(filename, outputfilename)
char *filename, *outputfilename;
{
register struct syment *sym, *end;
int i, n;
LDFILE *ldptr;
FILE *fp;
extern char *malloc();
ldptr = ldopen(filename, "r");
if (ldptr == NULL) {
fprintf(stderr, "Can't open %s\n", filename);
exit(1);
}
ldfhread(ldptr, &header);
if (header.f_opthdr != 0) {
fprintf(stderr, "Unexpected optional header.\n");
exit(1);
}
if (header.f_nscns < 3 || header.f_nscns > 8) {
fprintf(stderr, "Illegal number of sections.\n");
exit(1);
}
for (i = 1; i <= header.f_nscns; i++)
ldshread(ldptr, i, §ion[i]);
if (strcmp(section[1].s_name, ".text") != 0) {
fprintf(stderr, ".text not found.\n");
exit(1);
}
if (strcmp(section[2].s_name, ".data") != 0) {
fprintf(stderr, ".data not found.\n");
exit(1);
}
/*
The bss segment need not exist.
*/
/*
if (strcmp(section[3].s_name, ".bss") != 0) {
fprintf(stderr, ".bss not found.\n");
exit(1);
}
*/
if (section[1].s_size > 0 &&
section[1].s_scnptr !=
sizeof(struct filehdr) +
header.f_nscns*sizeof(struct scnhdr)) {
fprintf(stderr, "Contradictory text start.\n");
exit(1);
}
if (section[1].s_size > 0 && section[2].s_size > 0 &&
section[1].s_scnptr + section[1].s_size !=
section[2].s_scnptr) {
fprintf(stderr, "Contradictory data start.\n");
exit(1);
}
text = malloc(section[1].s_size + section[2].s_size);
FSEEK(ldptr, section[1].s_scnptr, 0);
FREAD(text, 1, section[1].s_size + section[2].s_size, ldptr);
ldtbseek(ldptr);
symbol_table
= (struct syment *)malloc(sizeof(struct syment) * header.f_nsyms);
/*
sizeof(struct syment) and SYMESZ are not always the same.
*/
for (i = 0; i < header.f_nsyms; i++)
FREAD(&symbol_table[i], SYMESZ, 1, ldptr);
/*
If the string table is not empty,
its length is stored after the symbol table,
This is not described in the manual, and may change in the future.
*/
if (FREAD(&i, 4, 1, ldptr) > 0) {
string_table = malloc(i);
FSEEK(ldptr, -4, 1);
FREAD(string_table, 1, i, ldptr);
}
end = symbol_table + header.f_nsyms;
for (sym = symbol_table; sym < end; sym++) {
switch (sym->n_scnum) {
case 1: case 2: case 3:
/*
If the section number of the symbol is 1, 2, or 3,
the start address of the text is stored.
This is not described in the manual,
and may depend on CPU or may change in the future.
*/
sym->n_value = (int)start_address;
break;
case N_UNDEF:
search_symbol(sym);
break;
default:
/*
Does nothing. Is it OK?
*/
break;
}
sym += sym->n_numaux;
}
ldrseek(ldptr, 1);
for (i = 0; i < section[1].s_nreloc; i++) {
/*
FREAD(&relocation_info, sizeof(struct reloc), 1, ldptr);
*/
FREAD(&relocation_info, 10, 1, ldptr);
relocate();
}
ldrseek(ldptr, 2);
for (i = 0; i < section[2].s_nreloc; i++) {
/*
FREAD(&relocation_info, sizeof(struct reloc), 1, ldptr);
*/
FREAD(&relocation_info, 10, 1, ldptr);
relocate();
}
fp = fopen(outputfilename, "w");
if (fp == NULL) {
fprintf(stderr, "Can't creat %s.\n", outputfilename);
exit(1);
}
fwrite(&header, sizeof(struct filehdr), 1, fp);
for (i = 1; i <= header.f_nscns; i++)
fwrite(§ion[i], sizeof(struct scnhdr), 1, fp);
fwrite(text, 1, section[1].s_size + section[2].s_size, fp);
fclose(fp);
ldclose(ldptr);
}
search_symbol(sym)
register struct syment *sym;
{
register struct syment *p, *end;
end = my_symbol_table + my_header.f_nsyms;
for (p = my_symbol_table; p < end; p++) {
/*
Is the following check enough?
*/
if (1 <= p->n_scnum && p->n_scnum <= 3 &&
p->n_sclass == C_EXT &&
(sym->n_zeroes == 0
? (p->n_zeroes == 0 &&
strcmp(&my_string_table[p->n_offset],
&string_table[sym->n_offset]) == 0)
: (p->n_zeroes != 0 &&
strncmp(p->n_name, sym->n_name, SYMNMLEN) == 0)))
goto FOUND;
p += p->n_numaux;
}
sym->n_name[SYMNMLEN] = '\0';
fprintf(stderr, "%s: undefined symbol.\n",
(sym->n_zeroes ? sym->n_name : &string_table[sym->n_offset]));
exit(1);
FOUND:
/*
Subtract the original value.
This is not described in the manual,
and I don't understand why.
*/
sym->n_value = p->n_value - sym->n_value;
}
relocate()
{
char *where, *p;
int value;
where = text + relocation_info.r_vaddr;
if (relocation_info.r_type == R_ABS)
return;
/*
The following code depends on CPU.
*/
if (relocation_info.r_type != R_DIR32S) {
fprintf(stderr, "%d: unsupported relocation type.",
relocation_info.r_type);
exit(1);
}
/*
Assuming R_DIR32S.
*/
p = (char *)(&value);
p[3] = where[0];
p[2] = where[1];
p[1] = where[2];
p[0] = where[3];
value += symbol_table[relocation_info.r_symndx].n_value;
where[0] = p[3];
where[1] = p[2];
where[2] = p[1];
where[3] = p[0];
}